# -*- coding: utf-8 -*-
from abc import ABCMeta, abstractmethod
from dtrader import logger
import json,time
import threading

from dtrader.portfolio.portfolio import Portfolio
from dtrader.trade.livetrade import LiveTrade


class AbstractStrategy(object):
    """
    AbstractStrategy是一个抽象类为子类提供接口的
    策略模块的目标是根据行情模块（PriceHandler）提供的数据产生交易信号，
    推送到事件消息队列中，策略模块设计可以同时被回测模块和实盘模块使用
    """

    __metaclass__ = ABCMeta

    LOGGER_NAME = "strategy"

    def __init__(self,price_handler,broker):
        """
        :param price_handler:
        :type price_handler dtrader.price_handler.AbstractPriceHandler
        :param broker:
        :type broker dtrader.broker.BaseBroker
        """
        self.__broker = broker
        self.__logger = logger.getLogger(self.LOGGER_NAME)
        self.__price_handler = price_handler


    def get_logger(self):
        return self.__logger

    def get_broker(self):
        return self.__broker

    def get_price_handler(self):
        return self.__price_handler

    def set_portfoliohandler(self,portfoliohandler):
        self.portfoliohandler = portfoliohandler

    @abstractmethod
    def on_tick(self, event):
        """
        有新的tick数据后会触发事件
        :param event: tick事件
        :return:
        """
        raise NotImplementedError("Should implement on_tick()")

    @abstractmethod
    def on_bar(self,event):
        """
        有新的bar事件后会触发
        :param event: bar事件
        :return:
        """
        raise NotImplementedError("Should implement on_tick()")




class LiveTradeStrategy(AbstractStrategy):
    """
    交易策略
    """
    def __init__(self,price_handler,broker):

        super(LiveTradeStrategy, self).__init__(price_handler,broker)

        # 初始化投资组合
        positions = self.get_broker().get_positions_from_broker()
        cash = self.get_broker().get_cash()
        self.__portfolio = Portfolio(price_handler, cash, *positions)

    def get_portfolio(self):
        return self.__portfolio

    def create_limit_order(self,ticker,action,quantity,limit_price):
        """
        现价单
        :param ticker: 标的
        :param action: 下单动作，买/卖(BOT/SLD)
        :param quantity: 数量
        :param limit_price: 价格
        :return:_or
        """
        order = self.get_broker().create_limit_order(ticker,action,quantity,limit_price)
        if order:
            self.get_broker().submit_order(order)
            return True
        else:
            return False

    def create_market_order(self,ticker,action,quantity):

        order = self.get_broker().create_market_order(ticker,action,quantity)
        if order:
            self.get_broker().submit_order(order)
        else:
            return False

    def run(self):
        """
        运行策略
        """

        #run the pricehandler

        # start price thread
        price_thread = threading.Thread(target=self.get_price_handler().fetch_tick_loop, args=[])
        price_thread.setDaemon(True)
        price_thread.start()
        self.get_logger().info("start the price thread")
        # start trader thread
        live_trade = LiveTrade(self.get_price_handler(), self.get_portfolio(), self)
        trade_thread = threading.Thread(target=live_trade.trade, args=[])
        trade_thread.setDaemon(True)
        trade_thread.start()
        self.get_logger().info("start the trade thread")

        #evnet loop
        while 1:
            time.sleep(100)


class BackTestStrategy(AbstractStrategy):
    """
    回测策略
    """
    pass



class Strategies(AbstractStrategy):
    """
    Strategies是一个策略的集合类
    """
    def __init__(self, *strategies):
        self._lst_strategies = strategies

    def on_tick(self, event):
        for strategy in self._lst_strategies:
            strategy.on_tick(event)

    def on_bar(self, event):
        for strategy in self._lst_strategies:
            strategy.on_bar(event)

    def set_portfoliohandler(self,portfoliohandler):
        for strategy in self._lst_strategies:
            strategy.set_portfoliohandler(portfoliohandler)

    def parse_option(self,json_str):
        pass
    def get_tickers(self):
        tickers = []
        for strategy in self._lst_strategies:
            tmp_tickers = strategy.get_tickers()
            tickers.extend(tmp_tickers)
        tickers = list(set(tickers))
        return tickers



